package com.imooc.girl.utils;

import javassist.*;
import javassist.bytecode.CodeAttribute;
import javassist.bytecode.LocalVariableAttribute;
import javassist.bytecode.MethodInfo;

import javax.servlet.http.HttpServletRequest;

/**
 * @description: 切面工具类
 * @program: girl
 * @author: Administrator
 * @date: 2019/2/19 10:33
 */
public class AspectUtils {

    private AspectUtils() {}

    /**
     * 获取客户端真实ip
     * @param request
     * @return
     */
    public static String getRemoteAddr(HttpServletRequest request) {
        String ip = request.getHeader("x-forwarded-for");
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("Proxy-Client-IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("WL-Proxy-Client-IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getRemoteAddr();
        }
        return ip;
    }

    /**
     * 得到方法参数名
     * @param cls   当前调用类的类类型
     * @param targetClazzName    目标方法的类名
     * @param targetMethodName    目标方法的方法名
     * @return
     * @throws NotFoundException
     */
    public static String[] getFieldsName(Class<?> cls, String targetClazzName, String targetMethodName) throws NotFoundException {
        // 启动ClassPool容器池
        ClassPool pool = ClassPool.getDefault();
        // 将目标类的字节码手动添加到ClassPool, 防止web环境notfound
        ClassClassPath classPath = new ClassClassPath(cls);
        pool.insertClassPath(classPath);

        CtClass cc = pool.get(targetClazzName);
        // 引用的CtClass中根据方法名拿到CtMethod声明方法
        CtMethod cm = cc.getDeclaredMethod(targetMethodName);
        // 返回代表该声明方法的methodInfo
        MethodInfo methodInfo = cm.getMethodInfo();
        // 获取方法的代码属性
        CodeAttribute codeAttribute = methodInfo.getCodeAttribute();
        // 返回指定属性(LocalVariableTable)的值
        LocalVariableAttribute attr = (LocalVariableAttribute) codeAttribute.getAttribute(LocalVariableAttribute.tag);
        // 确定参数个数
        String[] paramNames = new String[cm.getParameterTypes().length];
        int pos = Modifier.isStatic(cm.getModifiers()) ? 0 : 1;
        for (int i = 0; i < paramNames.length; i++) {
            // 拿到参数名称
            paramNames[i] = attr.variableName(i + pos);
        }
        return paramNames;
    }

    /**
     * 拼接参数字符串
     * @param args
     * @param paramsName
     * @return
     */
    public static String getArgsString(Object[] args, String[] paramsName) {
        if (args != null && args.length == 0) {
            return "{}";
        }
        StringBuffer sb = new StringBuffer("{");
        int i = 0;
        for (String param : paramsName) {
            sb.append(param).append(":\"").append(args[i++]).append("\", ");
        }
        String sbStr = sb.substring(0, sb.length() - 2);
        return sbStr + "}";
    }
}
